package 第十一章_网络编程.第十一章_网络编程_简易版中继站;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
    public static void main(String[] args) throws IOException {
        //申请了一个vector的容器 对象 vector 类型为UserThread
        Vector<UserThread> vector=new Vector<>();
        //申请 线程池管理对象 es  线程数5
        final ExecutorService es = Executors.newFixedThreadPool(5);
        //申请 服务拼接字对象 server 端口为8888
        ServerSocket server=new ServerSocket(8888);
        System.out.println("服务器已经启动,正在等待客户端的连接...");
        //开启运行服务器的服务
        while(true){
            //申请 拼接字的对象 socket 等待 它.串行功能 与其他客户端进行对接
            Socket socket = server.accept();
            //申请 客户端的线程处理对象 user  把 socket 和vector当成 初始成员进行构造
            UserThread user=new UserThread(socket,vector);
            //es 执行 类型为user
            es.execute(user);
        }
    }
}
class UserThread implements Runnable{
    //此类中有2个秘书 vector 和socket 负责处理内部线程规则事宜
    //6个字段 1.vector 集合容器，2.socket 拼接字 3.name (dist target) 4.ois 对象读取流 5.对象输出流 6.flag 信标
    //使用了容器 包装的是一个自定义的类，所以使用 对象输出输入流
    private Vector<UserThread> vector;
    private Socket socket;
    private String name; //客户端的目标用户名称（类似公司员工工号）
    private ObjectInputStream ois;
    private ObjectOutputStream oos;
    boolean flag=true;

    public UserThread() {

    }

    public UserThread(Socket socket, Vector<UserThread> vector){
        this.socket=socket;
        this.vector=vector;
        //在构造UserThread 的时候 它 把class这个类都放进去了。
        vector.add(this);
    }
    @Override
    public void run() {
        //打印客户端ip地址
        System.out.println("客户端已经登入,ip地址是: "+socket.getInetAddress().getHostAddress());
        try {
            //设置2个渠道ois 和oos    将类中的拼接字对象socket的字节流 赋值给 对象输出输入流对象
            ois=new ObjectInputStream(socket.getInputStream());
            oos=new ObjectOutputStream(socket.getOutputStream());
            while(flag){
                //对象输入流 和 自定义的Message 都继承了seriali'za'b'le接口
                //下面的注释这句 是 使用 object 通用类的tostring 方法 确认ois的对象封装格式
                //System.out.println("o.tostring: "+ois.readObject().toString());
                //将object类型 转换成message 类型 和输入的类型一致  此自定义类型需要serializable 接口进行 序列化和反序列化传输
                Message msg=(Message)ois.readObject();
                int type=msg.getType();
                switch (type){
                    case MessageType.TYPE_LOGIN:
                        name=msg.getFrom();
                        msg.setInfo("欢迎你: ");
                        oos.writeObject(msg);
                        break;
                        //如果是转发消息 就把从ois 中封装的 msg 的 to字段的
                    case MessageType.TYPE_SEND:
                        String to=msg.getTo();
                        UserThread ut;
                        int size = vector.size();
                        for(int i = 0; i< size; i++){
                            ut=vector.get(i);
                            if(to.equals(ut.name)&& ut!=this){
                                ut.oos.writeObject(msg);
                                break;
                            }
                        }
                        break;
                }
            }
            oos.close();
            ois.close();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

    }
}
